package com.neusoft.hifly.core.log.aop;

import java.lang.reflect.Method;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.neusoft.hifly.commons.lang.StringConstants;
import com.neusoft.hifly.commons.lang.StringUtil;
import com.neusoft.hifly.commons.web.WebUtil;
import com.neusoft.hifly.core.config.SystemConfig;
import com.neusoft.hifly.core.log.Log;
import com.neusoft.hifly.core.log.annotation.LogType;
import com.neusoft.hifly.core.log.annotation.OperationLog;
import com.neusoft.hifly.core.token.TokenContextHolder;
import com.neusoft.hifly.core.token.domain.TokenVO;

/**
 * Title: 核心类库
 * <p>
 * Description: 操作日志 自定义注解
 * <p>
 * Copyright: 2019
 * <p>
 * Company: 东软汉枫
 *
 * @author lh_neu
 * @version 1.0.0
 */
@Aspect
@Component
public class LogAnnotationAop {

	@Autowired(required = false)
	private SystemConfig systemConfig;

	/** * @within匹配类上的注解 * @annotation匹配方法上的注解 */
	@Pointcut("@within(com.neusoft.hifly.core.log.annotation.OperationLog) || @annotation(com.neusoft.hifly.core.log.annotation.OperationLog)")
	public void operationLog() {
	}

	@Before(value = "operationLog()")
	public void beforeOpt(final JoinPoint point) throws Throwable {
		try {

			final Object target = point.getTarget();
			final Class<?> clazz = target.getClass();
			final Method[] methods = clazz.getMethods();
			OperationLog annotation = null;
			for (final Method method : methods) {
				if (point.getSignature().getName().equals(method.getName())) {
					annotation = method.getAnnotation(OperationLog.class);
					if (annotation == null) {
						annotation = point.getTarget().getClass().getAnnotation(OperationLog.class);
						if (annotation != null) {
							break;
						}
					} else {
						break;
					}
				}
			}
			if (annotation == null) {
				return;
			}
			final ServletRequestAttributes req = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
			if (req == null) {
				return;
			}
			final HttpServletRequest request = req.getRequest();
			if (request == null) {
				return;
			}
			final Object[] objects = point.getArgs();
			if (objects == null || objects.length == 0) {
				return;
			}
			final List<Object> params = Lists.newArrayList();
			for (final Object object : objects) {
				if (object instanceof HttpServletRequest) {
					continue;
				}
				params.add(object);
			}
			String type = "";
			if (LogType.SAVE == annotation.method()) {
				type = "保存";
			} else if (LogType.UPDATE == annotation.method()) {
				type = "更新";
			} else if (LogType.DELETE == annotation.method()) {
				type = "删除";
			} else if (LogType.PHYSICS == annotation.method()) {
				type = "物理删除";
			} else if (LogType.RECOVER == annotation.method()) {
				type = "还原";
			}
			saveToFile(type + "[" + annotation.msg() + "]成功!" + JSON.toJSONString(params), type,
					WebUtil.getIpAddr(request), WebUtil.getWebUrl(request));
		} catch (final Exception e) {
			e.printStackTrace();
			Log.error("写入操作日志失败：" + e.getMessage());
		}

	}

	/**
	 * 保存数据到文件
	 * 
	 * @param message
	 *            日志信息
	 * @param operate
	 *            日志类别
	 * @param ip
	 *            IP
	 * @param url
	 *            URL
	 */
	@Async
	private void saveToFile(final String message, final String operate, final String ip, final String url) {
		String loginName = "无";

		final TokenVO tokenVO = TokenContextHolder.get();

		if (tokenVO != null) {
			// 发布系统中的用户
			loginName = tokenVO.getLoginName();
		}

		String sysName = "";

		if (systemConfig != null) {
			sysName = systemConfig.getSysName() + sysName;
		}

		// 写入日志文件（逗号分隔），便于工具抓取（HDFS抓取）
		final StringBuffer sb = new StringBuffer("");
		sb.append(loginName);
		sb.append(StringConstants.STRING_SPLIT_FLAG_3);
		sb.append(ip);
		sb.append(StringConstants.STRING_SPLIT_FLAG_3);
		sb.append(url);
		sb.append(StringConstants.STRING_SPLIT_FLAG_3);
		sb.append(sysName);
		sb.append(StringConstants.STRING_SPLIT_FLAG_3);
		sb.append(StringUtil.getTraceInfo());
		sb.append(StringConstants.STRING_SPLIT_FLAG_3);
		sb.append(operate);
		sb.append(StringConstants.STRING_SPLIT_FLAG_3);
		sb.append(message);
		Log.info(sb.toString());

	}
}
